package com.gitee.limaozhi.socket.lesson03.example2;

import com.gitee.limaozhi.socket.lesson02.example3.LineDelimiterDecoder;
import com.gitee.limaozhi.socket.lesson03.example1.LineDelimiterEncoder;
import com.gitee.limaozhi.socket.lesson03.example1.ServerLogicHandler;
import com.gitee.limaozhi.util.Utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author hzlimaozhi
 * @date 2019/08/26 15:57
 */
public class ServerHandler {

    private static AtomicInteger ClientCount = new AtomicInteger(0);

    private Socket socket;
    private String name;
    private ExecutorService executorService;

    private InputStream inputStream;
    private OutputStream outputStream;
    private LineDelimiterDecoder delimiterDecoder;
    private StringBuilder stringBuilder = new StringBuilder();

    private AtomicBoolean stop = new AtomicBoolean(false);
    private AtomicInteger requestCount = new AtomicInteger(0);
    private Map<Integer, ServerResponse> responseMap = new HashMap<>();
    private AtomicInteger responseCount = new AtomicInteger(0);

    public ServerHandler(Socket socket, ExecutorService executorService) {
        this.socket = socket;
        this.name = "" + ClientCount.incrementAndGet();
        this.executorService = executorService;
    }

    public void start() {
        try {
            inputStream = socket.getInputStream();
            outputStream = socket.getOutputStream();
            delimiterDecoder = new LineDelimiterDecoder();

            byte[] buffer = new byte[1024];
            while (true) {
                int count = inputStream.read(buffer);
                if (count == -1) {
                    // 请求结束
                    stop.set(true);
                    break;
                }

                List<String> requests = delimiterDecoder.decode(Utils.copy(buffer, 0, count));
                for (String request : requests) {
                    int requestId = requestCount.incrementAndGet();
                    executorService.submit(() -> {
                        print("客户端" + name + "：" + request);

                        String response = ServerLogicHandler.getResponse(request);
                        print("服务器" + name + "：" + response);

                        output(new ServerResponse(requestId, response));
                    });
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            stop();
        }
    }

    public synchronized void output(ServerResponse response) {
        responseMap.put(response.getRequestId(), response);

        while (true) {
            if (stop.get() && responseCount.intValue() >= requestCount.intValue()) {
                stop();
                return;
            }

            // 按请求顺序发送
            int nextResponseId = responseCount.get() + 1;
            ServerResponse serverResponse = responseMap.remove(nextResponseId);
            if (serverResponse == null) {
                return;
            }
            responseCount.incrementAndGet();

            try {
                byte[] responseBytes = LineDelimiterEncoder.encode(serverResponse.getResponse());
                outputStream.write(responseBytes);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void stop() {
        try {
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        print("客户端" + name + "：关闭");
        System.out.println(stringBuilder.toString());
    }

    private synchronized void print(String content) {
        stringBuilder.append(content + "\n");
//        System.out.println(content);
    }

}
